#pragma once

#include"TestGraphes.h"
#include"GraphAlgorithms.h"
#include<set>
#include<vector>
#include<stdexcept>
#include<algorithm>
#include<crtdbg.h>
#include<fstream>
#include<iostream>
#include<Windows.h>
#include<string>


void listGraphesUnitCheck(){
	{
		int vertexNum = 0;
		int edgesNum = 0;
		std::vector<Edge >edgesList;
		ListGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "list");
	}
	{
		int vertexNum = 100;
		int edgesNum = 0;
		std::vector<Edge >edgesList;
		ListGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "list");
	}
	{
		int vertexNum = 4;
		int edgesNum = 2;
		std::vector<Edge >edgesList{ { 0, 1 }, { 2, 3 } };
		ListGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "list");
	}
	{
		int vertexNum = 10;
		int edgesNum = 15;
		std::vector<Edge >edgesList;
		for (int currentVertex = 0; currentVertex < vertexNum; ++currentVertex){
			edgesList.push_back({ currentVertex, (currentVertex + 1) % vertexNum });
		}
		for (int currentVertex = 0; currentVertex < 5; ++currentVertex){
			edgesList.push_back({ currentVertex, currentVertex + 5 });
		}
		ListGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "list");
	}

}
void matrixGraphesUnitCheck(){
	{
		int vertexNum = 0;
		int edgesNum = 0;
		std::vector<Edge >edgesList;
		MatrixGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "matrix");
	}
	{
		int vertexNum = 100;
		int edgesNum = 0;
		std::vector<Edge >edgesList;
		MatrixGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "matrix");
	}
	{
		int vertexNum = 4;
		int edgesNum = 2;
		std::vector<Edge>edgesList{ { 0, 1 }, { 2, 3 } };
		MatrixGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "matrix");
	}
	{
		int vertexNum = 10;
		int edgesNum = 15;
		std::vector<Edge >edgesList;
		for (int currentVertex = 0; currentVertex < vertexNum; ++currentVertex){
			edgesList.push_back({ currentVertex, (currentVertex + 1) % vertexNum });
		}
		for (int currentVertex = 0; currentVertex < 5; ++currentVertex){
			edgesList.push_back({ currentVertex, currentVertex + 5 });
		}
		MatrixGraph G(vertexNum, edgesList);
		graphesAdjacentCheck(G, edgesList, "matrix");
	}
}
#ifdef _DEBUG
	void detectedMemoryLeaks(const std::string& testType){
		throw std::runtime_error("Detected memory leaks on " + testType);
	}

	void memoryLeaksListUnitTests(){
		{
			int vertexNum = 0;
			int edgesNum = 0;
			std::vector<Edge >edgesList;
			memoryLeaksCheck<ListGraph>(vertexNum, edgesList, "list");
		}
		{
			int vertexNum = 100;
			int edgesNum = 0;
			std::vector<Edge >edgesList;
			memoryLeaksCheck<ListGraph>(vertexNum, edgesList, "list");
		}
		{
			int vertexNum = 4;
			int edgesNum = 2;
			std::vector<Edge >edgesList{ { 0, 1 }, { 2, 3 } };
			memoryLeaksCheck<ListGraph>(vertexNum, edgesList, "list");
		}
		{
			int vertexNum = 10;
			int edgesNum = 15;
			std::vector<Edge >edgesList;
			for (int currentVertex = 0; currentVertex < vertexNum; ++currentVertex){
				edgesList.push_back({ currentVertex, (currentVertex + 1) % vertexNum });
			}
			for (int currentVertex = 0; currentVertex < 5; ++currentVertex){
				edgesList.push_back({ currentVertex, currentVertex + 5 });
			}
			memoryLeaksCheck<ListGraph>(vertexNum, edgesList, "list");
		}
	}
	void memoryLeaksMatrixUnitTests(){
		{
			int vertexNum = 0;
			int edgesNum = 0;
			std::vector<Edge >edgesList;
			memoryLeaksCheck<MatrixGraph>(vertexNum, edgesList, "matrix");
		}
		{
			int vertexNum = 100;
			int edgesNum = 0;
			std::vector<Edge >edgesList;
			memoryLeaksCheck<MatrixGraph>(vertexNum, edgesList, "matrix");
		}
		{
			int vertexNum = 4;
			int edgesNum = 2;
			std::vector<Edge >edgesList{ { 0, 1 }, { 2, 3 } };
			memoryLeaksCheck<MatrixGraph>(vertexNum, edgesList, "matrix");
		}
		{
			int vertexNum = 10;
			int edgesNum = 15;
			std::vector<Edge >edgesList;
			for (int currentVertex = 0; currentVertex < vertexNum; ++currentVertex){
				edgesList.push_back({ currentVertex, (currentVertex + 1) % vertexNum });
			}
			for (int currentVertex = 0; currentVertex < 5; ++currentVertex){
				edgesList.push_back({ currentVertex, currentVertex + 5 });
			}
			memoryLeaksCheck<MatrixGraph>(vertexNum, edgesList, "matrix");
		}
	}
	size_t compactGraphMemoryCount(int vertexNum, const std::vector<Edge > & edgesList){
		_CrtMemState memoryStateBeforeCreating;
		_CrtMemState memoryStateAfterCreating;
		_CrtMemCheckpoint(&memoryStateBeforeCreating);

		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);

		_CrtMemCheckpoint(&memoryStateAfterCreating);
		_CrtMemState differenceMemory;
		_CrtMemDifference(&differenceMemory,
			&memoryStateBeforeCreating, &memoryStateAfterCreating);


		return differenceMemory.lTotalCount;
	}
	void graphChooseStressCheck(){
		for (int testNumber = 0; testNumber < 100; ++testNumber){
			int vertexNum;
			std::vector<Edge>  edgesList;
			generateScriptForGraph(vertexNum, edgesList);
			size_t listGraphSize = getPredictedListGraphSize(vertexNum, edgesList.size());
			size_t matrixGraphSize = getPredictedMatrixGraphSize(vertexNum);
			size_t realGraphSize = compactGraphMemoryCount(vertexNum, edgesList);
			std::cout << "list: " << listGraphSize << " matrix: " << matrixGraphSize << " real: " << realGraphSize << std::endl;
			if (std::min<size_t>(listGraphSize, matrixGraphSize) * 3 <= realGraphSize)
				throw std::logic_error("Poor use of memory");
		}
	}
	void memoryTestGraphes(const std::string& typeGraph, int vertexNum, const std::vector<Edge >&  edgesList){
		std::string outputFile = ".\\MemoryLogs\\" + typeGraph + ".log";
		std::ofstream out(outputFile.c_str(), std::ios::app);
		_CrtMemState beforeGraph;
		_CrtMemCheckpoint(&beforeGraph);
		{
			_CrtMemState memoryStateBeforeCreatingMatrix;
			_CrtMemState memoryStateAfterCreatingMatrix;
			_CrtMemCheckpoint(&memoryStateBeforeCreatingMatrix);

			MatrixGraph matrixRepresentation(vertexNum, edgesList);

			_CrtMemCheckpoint(&memoryStateAfterCreatingMatrix);
			_CrtMemState differenceMemoryMatrix;
			_CrtMemDifference(&differenceMemoryMatrix,
				&memoryStateBeforeCreatingMatrix, &memoryStateAfterCreatingMatrix);

			out << "Memory size used by " << typeGraph << " matrix graph on "
				<< vertexNum << " vertexes and " << edgesList.size() << " is " << differenceMemoryMatrix.lTotalCount << " bytes" << std::endl;
			

			_CrtMemState memoryStateBeforeCreatingList;
			_CrtMemState memoryStateAfterCreatingList;
			_CrtMemCheckpoint(&memoryStateBeforeCreatingList);

			ListGraph listRepresentation(vertexNum, edgesList);

			_CrtMemCheckpoint(&memoryStateAfterCreatingList);
			_CrtMemState differenceMemoryList;
			_CrtMemDifference(&differenceMemoryList,
				&memoryStateBeforeCreatingList, &memoryStateAfterCreatingList);

			out << "Memory size used by " << typeGraph << " list graph on "
				<< vertexNum << " vertexes and " << edgesList.size() << " is " << differenceMemoryList.lTotalCount << " bytes" << std::endl;


			_CrtMemState memoryStateBeforeCreating;
			_CrtMemState memoryStateAfterCreating;
			_CrtMemCheckpoint(&memoryStateBeforeCreating);

			std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);

			_CrtMemCheckpoint(&memoryStateAfterCreating);
			_CrtMemState differenceMemory;
			_CrtMemDifference(&differenceMemory,
				&memoryStateBeforeCreating, &memoryStateAfterCreating);

			out << "Memory size used by " << typeGraph << " graph on "
				<< vertexNum << " vertexes and " << edgesList.size() << " is " << differenceMemory.lTotalCount << " bytes" << std::endl;

		}
		_CrtMemState afterGraph;
		_CrtMemCheckpoint(&afterGraph);
		_CrtMemState differenceMemory;
		if (_CrtMemDifference(&differenceMemory, &beforeGraph, &afterGraph)){
			detectedMemoryLeaks(typeGraph + " graph");
		}
	}
	void memoryCheckEmptyGraph(){
		for (int testNum = 0; testNum <= 100; ++testNum){
			int vertexNum = testNum * 100;
			std::vector<Edge> edgesList;
			memoryTestGraphes("empty", vertexNum, edgesList);
		}
	}


	void memoryCheckFullGraph(){
		
		for (int vertexNum = 0; vertexNum < 200; ++vertexNum){
			
				std::vector<Edge > edgesList;
				for (int fromVertex = 0; fromVertex < vertexNum; ++fromVertex){
					for (int toVertex = fromVertex + 1; toVertex < vertexNum; ++toVertex){
						edgesList.push_back({ fromVertex, toVertex });
						edgesList.push_back({ toVertex, fromVertex });
					}
				}
				memoryTestGraphes("full", vertexNum, edgesList);
			
		}
	}
	void memoryCheckRandomGraph(){
		for (int testCount = 0; testCount < 50; ++testCount){
			int vertexNum = getRandomPositiveNumber() % 10000;
			int edgesNum = std::min<int>(getRandomPositiveNumber() % 100000, vertexNum * 10);
			std::vector<Edge > edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				edgesList.push_back(getRandomEdge(vertexNum));
			}
			memoryTestGraphes("random", vertexNum, edgesList);
		}
	}
	void memoryCheckAcyclicGraph(){
		for (int testCount = 0; testCount < 100; ++testCount){
			int vertexNum = std::max<int>(10, getRandomPositiveNumber() % 1000);
			int edgesNum = std::min<int>(getRandomPositiveNumber() % 10000, vertexNum * 10);
			std::vector<int> orderVertex(vertexNum);
			for (int counter = 0; counter < vertexNum; ++counter){
				orderVertex[counter] = counter;
			}
			std::random_shuffle(orderVertex.begin(), orderVertex.end());
			std::vector<Edge > edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				std::pair<int,int>  indexEdge = getRandomIndexes(vertexNum);
				edgesList.push_back({ orderVertex[indexEdge.first], orderVertex[indexEdge.second] });
			}
			memoryTestGraphes("acyclic", vertexNum, edgesList);
		}
	}
	void memoryCheckFunctionalGraphs(){
		for (int testCount = 0; testCount < 100; ++testCount){
			int vertexNum = getRandomPositiveNumber() % 10000;
			int edgesNum = vertexNum;
			std::vector<Edge > edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				edgesList.push_back({ edgesCount, getRandomPositiveNumber() % vertexNum });
			}
			memoryTestGraphes("functional", vertexNum, edgesList);
		}
	}

	
	

#endif


void unitTestsAdjacent(){
	{
		
		int vertexNum = 7;
		
		std::vector<Edge > edgesList = { { 0, 1 }, { 1, 2 }, { 2, 3 },
		{ 3, 4 }, { 4, 5 }, { 5, 3 }, { 2, 5 }, { 0, 4 }, { 0, 6 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		graphesAdjacentCheck(*G, edgesList, "unit compact");
	}
}


#ifndef _DEBUG
void timeCheckEmptyGraphs(){

	std::ofstream out(".\\TimeLogs\\empty.log");
	for (int vertexNum = 0; vertexNum < 100; ++vertexNum){
		{

			std::vector<Edge > edgesList;
			std::unique_ptr<Graph> G = readGraph(100 * vertexNum, edgesList);

			DefaultUserClass defClass;
			int time1 = GetTickCount();
			DFS(*G, &defClass);
			int time2 = GetTickCount();
			out << "Time used by DFS on empty graph on " << 100 * vertexNum <<
				" vertexes is " << (time2 - time1) << " ms" << std::endl;

		}
	}
	out.close();
} 






void timeCheckFullGraph(){
	std::ofstream out(".\\TimeLogs\\full.log");
	for (int vertexNum = 0; vertexNum < 200; ++vertexNum){
		{
			std::vector<Edge > edgesList;
			for (int fromVertex = 0; fromVertex < vertexNum; ++fromVertex){
				for (int toVertex = fromVertex + 1; toVertex < vertexNum; ++toVertex){
					edgesList.push_back({ fromVertex, toVertex });
					edgesList.push_back({ toVertex, fromVertex });
				}
			}
			std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
			DefaultUserClass defClass;
			int time1 = GetTickCount();
			DFS(*G, &defClass);
			int time2 = GetTickCount();

			out << "Time used by DFS on full graph on " << vertexNum <<
				" vertexes is " << (time2 - time1) << " ms" << std::endl;
		}

	}
	out.close();
}


void timeCheckRandomGraph(){
	std::ofstream out(".\\TimeLogs\\random.log");
	for (int testCount = 0; testCount < 50; ++testCount){
		int vertexNum = getRandomPositiveNumber() % 10000;
		int edgesNum = std::min<int>(getRandomPositiveNumber() % 100000, vertexNum * 10);

		{

			std::vector<Edge > edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				edgesList.push_back(getRandomEdge(vertexNum));
			}
			std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
			DefaultUserClass defClass;
			int time1 = GetTickCount();
			DFS(*G, &defClass);
			int time2 = GetTickCount();
			out << "Time used by DFS on random graph on " << vertexNum <<
				" vertexes and " << edgesNum << " edges is " << (time2 - time1) << " ms" << std::endl;

		}
	}
	out.close();
}


void timeAndTopologyCheckAcyclicGraph(){
	std::ofstream out(".\\TimeLogs\\acyclic.log");
	for (int testCount = 0; testCount < 100; ++testCount){
		int vertexNum = std::max<int>(10, getRandomPositiveNumber() % 1000);
		int edgesNum = std::min<int>(getRandomPositiveNumber() % 10000, vertexNum * 10);
		{
			std::vector<int> orderVertex(vertexNum);
			for (int counter = 0; counter < vertexNum; ++counter){
				orderVertex[counter] = counter;
			}
			std::random_shuffle(orderVertex.begin(), orderVertex.end());
			std::vector<Edge > edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				std::pair<int, int> indexEdge = getRandomIndexes(vertexNum);
				edgesList.push_back({ orderVertex[indexEdge.first], orderVertex[indexEdge.second] });
			}
			std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
			DefaultUserClass defClass;
			int time1 = GetTickCount();
			DFS(*G, &defClass);
			int time2 = GetTickCount();
			out << "Time used by DFS on acyclic graph on " << vertexNum <<
				" vertexes and " << edgesNum << " edges is " << (time2 - time1) << " ms" << std::endl;

			topologySortClass topologyHandler;
			DFS(*G, &topologyHandler);


			std::vector<int> sortResult = topologyHandler.getTopologyOrder();
			checkTopologySort(*G, sortResult);
		}
	}
	out.close();
}

void timeCheckFunctionalGraphs(){
	std::ofstream out(".\\TimeLogs\\functional.log");
	for (int testCount = 0; testCount < 100; ++testCount){
		int vertexNum = getRandomPositiveNumber() % 10000;
		int edgesNum = vertexNum;
		{

			std::vector<Edge> edgesList;
			for (int edgesCount = 0; edgesCount < edgesNum; ++edgesCount){
				edgesList.push_back({ edgesCount, getRandomPositiveNumber() % vertexNum });
			}
			std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);

			DefaultUserClass defClass;
			int time1 = GetTickCount();
			DFS(*G, &defClass);
			int time2 = GetTickCount();

			out << "Time used by DFS on functional graph on " << vertexNum <<
				" vertexes is " << (time2 - time1) << " ms" << std::endl;
		}
	}
	out.close();
}

#endif //_DEBUG

void unitTestsTopology(){
	{
		
		int vertexNum = 3;
		int edgesNum = 3;
		std::vector<Edge> edgesList = { { 2, 1 }, { 1, 0 }, { 2, 0 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		topologySortClass DAG;
		DFS(*G, &DAG);
		std::vector<int> sortResult = DAG.getTopologyOrder();
		std::vector<int> correctAnswer{ 2, 1, 0 };
		if (sortResult != correctAnswer){
			throw std::logic_error("Wrong answer on topology sort Unit test 1");
		}
	}
	{
		int vertexNum = 1;
		int edgesNum = 0;
		std::vector<Edge> edgesList;
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		topologySortClass DAG;
		DFS(*G, &DAG);
		std::vector<int> sortResult = DAG.getTopologyOrder();
		std::vector<int> correctAnswer{ 0 };
		if (sortResult != correctAnswer){
			throw std::logic_error("Wrong answer on topology sort Unit test 2");
		}
	}
	{
		int vertexNum = 8;
		int edgesNum = 10;
		std::vector<Edge> edgesList = { { 0, 1 }, { 0, 2 },
		{ 0, 3 }, { 1, 4 }, { 2, 4 }, { 3, 4 }, { 4, 5 }, { 4, 6 }, { 5, 7 }, { 6, 7 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		topologySortClass DAG;
		DFS(*G, &DAG);
		std::vector<int> sortResult = DAG.getTopologyOrder();
		std::sort(sortResult.begin() + 1, sortResult.begin() + 4);
		std::sort(sortResult.begin() + 5, sortResult.begin() + 7);
		std::vector<int> correctResult{ 0, 1, 2, 3, 4, 5, 6, 7 };
		if (sortResult != correctResult){
			throw std::logic_error("Wrong answer on topology sort Unit test 3");
		}
	}
}


void BFSUnitTests(){
	{
		
		int vertexNum = 3;
		int edgesNum = 3;
		std::vector<Edge> edgesList = { { 2, 1 }, { 1, 0 }, { 2, 0 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleBFSClass BFSOrder;
		BFS(*G, &BFSOrder);
		std::vector<int> BFSResult = BFSOrder.getBFSOrder();
		std::vector<int> correctAnswer{ 0,1,2 };
		if (BFSResult != correctAnswer){
			throw std::logic_error("Wrong answer BFS Unit test 1");
		}
	}
	{
		
		int vertexNum = 1;
		int edgesNum = 0;
		std::vector<Edge> edgesList;
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleBFSClass BFSOrder;
		BFS(*G, &BFSOrder);
		std::vector<int> BFSResult = BFSOrder.getBFSOrder();
		std::vector<int> correctAnswer{ 0 };
		if (BFSResult != correctAnswer){
			throw std::logic_error("Wrong answer on BFS Unit test 2");
		}
	}
	{
		
		int vertexNum = 12;
		int edgesNum = 13;
		std::vector<Edge> edgesList = { { 0, 1 }, { 0, 2 },
		{ 0, 3 }, { 1, 4 }, { 2, 4 }, { 3, 4 }, { 4, 5 }, { 4, 6 }, { 5, 7 }, { 6, 7 }, { 3, 8 }, { 9, 11 }, { 10, 11 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleBFSClass BFSOrder;
		BFS(*G, &BFSOrder);
		std::vector<int> BFSResult = BFSOrder.getBFSOrder();
		std::vector<int> correctAnswer{ 0,1,2,3,4,8,5,6,7,9,11,10 };
		if (BFSResult != correctAnswer){
			throw std::logic_error("Wrong answer on BFS Unit test 3");
		}
	}
}

void DFSUnitTests(){
	{

		int vertexNum = 3;
		int edgesNum = 3;
		std::vector<Edge> edgesList = { { 2, 1 }, { 1, 0 }, { 2, 0 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleDfsClass dfsOrder;
		DFS(*G, &dfsOrder);
		std::vector<int> DFSResult = dfsOrder.getDFSOrder();
		std::vector<int> correctAnswer{ 0, 1, 2 };
		if (DFSResult != correctAnswer){
			throw std::logic_error("Wrong answer DFS Unit test 1");
		}
	}
	{

		int vertexNum = 1;
		int edgesNum = 0;
		std::vector<Edge> edgesList;
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleDfsClass dfsOrder;
		DFS(*G, &dfsOrder);
		std::vector<int> DFSResult = dfsOrder.getDFSOrder();
		std::vector<int> correctAnswer{ 0 };
		if (DFSResult != correctAnswer){
			throw std::logic_error("Wrong answer on DFS Unit test 2");
		}
	}
	{

		int vertexNum = 12;
		int edgesNum = 13;
		std::vector<Edge> edgesList = { { 0, 1 }, { 0, 2 },
		{ 0, 3 }, { 1, 4 }, { 2, 4 }, { 3, 4 }, { 4, 5 }, { 4, 6 }, { 5, 7 }, { 6, 7 }, { 3, 8 }, { 9, 11 }, { 10, 11 } };
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		SimpleDfsClass dfsOrder;
		DFS(*G, &dfsOrder);
		std::vector<int> BFSResult = dfsOrder.getDFSOrder();
		std::vector<int> correctAnswer{ 0, 3, 8, 4, 6, 7, 5, 2, 1, 9, 11, 10 };
		if (BFSResult != correctAnswer){
			throw std::logic_error("Wrong answer on DFS Unit test 3");
		}
	}
}

class InsideDFSCheck{
	std::set<int> setOfGreyVertexes_;
	std::set<int> setOfBlackVertexes_;
	std::set<Edge> setOfVisitedEdges_;
	size_t numberOfVertexes_;
public:
	explicit InsideDFSCheck(int numberOfVertexes_) : numberOfVertexes_(numberOfVertexes_){}

	const void beforeStep(int vertex) const {}

	void processEdge(int toVertex, int fromVertex, colors color){
		if (color == WHITE){
			if (!setOfGreyVertexes_.insert(toVertex).second){
				throw std::logic_error("White vertex became grey at least two times in DFS");
			}
		}
		if (fromVertex != -1){
			if (!setOfVisitedEdges_.insert(Edge(fromVertex, toVertex)).second){
				throw std::logic_error("We went by the same edge");
			} 
		}
	}

	void afterCurrentStep(int vertex, int parent){
		if (!setOfBlackVertexes_.insert(vertex).second){
			throw std::logic_error("White vertex became black at least two times in DFS");
		}
	}


	const void afterDFS() const {
		std::vector<int> listOfGreyVertexes;
		std::vector<int> listOfBlackVertexes;
		for (auto currentGreyVertex : setOfGreyVertexes_){
			listOfGreyVertexes.push_back(currentGreyVertex);
		}
		for (auto currentBlackVertex : setOfBlackVertexes_){
			listOfBlackVertexes.push_back(currentBlackVertex);
		}
		if (listOfBlackVertexes.size() != numberOfVertexes_){
			throw std::logic_error("There isn't equal amount of black vertexes");
		}
		if (listOfGreyVertexes.size() != numberOfVertexes_){
			throw std::logic_error("There isn't equal amount of vertexes that became grey");
		}
		for (int currentVertex = 0; currentVertex < numberOfVertexes_; ++currentVertex){
			if (listOfBlackVertexes[currentVertex] != currentVertex){
				throw std::logic_error("There isn't needed grey vertex");
			}
			if (listOfGreyVertexes[currentVertex] != currentVertex){
				throw std::logic_error("There isn't needed black vertex");
			}
		}	 
	}
	

	const void checkEdgesPath(std::vector<Edge>& edgesList) const{
		std::vector<Edge> usedEdges;
		for (auto currentEdge : setOfVisitedEdges_){
			usedEdges.push_back(currentEdge);
		}
		std::sort(edgesList.begin(), edgesList.end());
		auto lastIterator = std::unique(edgesList.begin(), edgesList.end());
		edgesList.resize(std::distance(edgesList.begin(), lastIterator));
		if (usedEdges.size() != edgesList.size()){
			throw std::logic_error("There isn't need number of visited edges");
		}
		for (size_t currentEdgeNum = 0; currentEdgeNum < edgesList.size(); ++currentEdgeNum){
			if (!(usedEdges[currentEdgeNum] == edgesList[currentEdgeNum])){
				throw std::logic_error("Not the same edge");
			}
		}
	}

	
};
void DFSInsideCheck(){
	for (int testCount = 0; testCount < 100; ++testCount){
		int vertexNum;
		std::vector<Edge> edgesList;
		generateScriptForGraph(vertexNum, edgesList);
		std::unique_ptr<Graph> G = readGraph(vertexNum, edgesList);
		InsideDFSCheck checkClass(vertexNum);
		DFS(*G, &checkClass);
		checkClass.checkEdgesPath(edgesList);
	}
}
